#
# CVSCustom.py
#
# Custom Menu support for SNiFF+ 3.x CVS Adapter
#
# Author: Martin Oberhuber
# Copyright (c) 1998, 1999 TakeFive Software, Salzburg
#
# Revisions:
#

import os, string, regsub, regex, sys, time, traceback
import vcs
from vcs import TEST, TRUE, FALSE, NL, SYSTEM, WINDOWS, UNIX
from vcs import NULLDEV, DELIMITER
# for Sniffaccess
import etgui

import CVS
import CVSPrefs
import CVSCore
import CVSDialogs

# Modules required for the Dialogs
#from etgui import *
#from PageLayout import *
#import CmdNo
#import ListEditor

# ----- Custom Menu support ---------------------------------------------------

def InitProjects(absProjDir, RWE, PWE, SSWEs):
	"""Initialize projects"""
	try:
		CVSCore.InitProjects(absProjDir, RWE, PWE, SSWEs)
	except:
		print "Exception caught:"
		traceback.print_exc()

def DoSingleCommand(cmd):
	if CVSPrefs.TEST:
		print "(CVSCustom) DoSingleCommand (",cmd,")"

	theSemi = string.find(cmd,";")
	if theSemi > 0 and len(cmd) > theSemi+9 and cmd[theSemi:theSemi+9] == "; cvs tag":
		try:
			# get the tag name that should be set or deleted!
			# this is what TagFiles() does:
			############
			#if doForce:
			#	cmd = "cvs tag -F -c " + theLabel + " "
			#else:
			#	cmd = "cvs tag -c " + theLabel + " "
			############
			# so this is what we need:
			if cmd[theSemi+10:theSemi+12] == "-F":
				theLabelList = string.split(cmd[theSemi+16:])
			else:
				theLabelList = string.split(cmd[theSemi+13:])
		
			theLabel = theLabelList[0]
			theFilename = theLabelList[1]
			#(workingDir,workingFile) = os.path.split(theFilename)
			workingDir = cmd[3:theSemi]
			workingFile = theFilename
				
			# make sure that the tag requested does not already exist as a branch tag!
			if len(theLabel) < 16 or theLabel[:16] != "SNIFF_CHANGESET_":
				# look for the symbol as a branch name!
				result = CVS.cvsRevisionOfSymbol(workingDir, workingFile, "SNIFF_BRANCH_"+theLabel)
				if result:
					# ouch, it exists as a branch!
					# CVSDialogs.ErrorDialog()
					out = "(DoSingleCommand) (cvs tag) Error: Symbol " + theLabel
					out = out +" exists already as a branch name in file @B" + workingFile 
					out = out + "@B cannot set the symbol!" + NL
					return out
		except:
			print "(DoSingleCommand) tagging -- exception caught!"
			traceback.print_exc()
			return "(DoSingleCommand) Exception caught on " + cmd +NL

	(rc, out, err) = CVSCore.GetStatusOutput(cmd)
	if not vcs.test(rc):
		print "(CVSCustom) DoSingleCommand: ", cmd
		print "(CVSCustom) DoSingleCommand: Error (",rc,"): ", err
	return out

def MultiFileCommand(theCommand, fileList, showOutput=0, canOptimize=1, postCommand=""):
	"""Execute a simple command on a list of REAL files, following symlinks;
	Loop for all files in fileList. It seems to be easier to read the 
	target of each symlink than to construct the real root from the 
	PWEs/SSWEs since the relative file path is not available in custom menus!
	Try to group files up to a maximum commandline length. Execute postCommand
	after all files have been processed. Return the output."""
	marker = "(CVSCustom) MultiFileCommand: "
	theOutput=""
	realFiles=[]
	for theFile in string.split(fileList):
		realFile = CVSCore.real_path_of_file(theFile)
		if realFile:
			if canOptimize:
				realFiles.append(realFile)
			else:
				(dir, file) = os.path.split(realFile)
				out = DoSingleCommand("cd "+dir+"; " + theCommand + " " + file)
				theOutput = theOutput+out
	if CVSPrefs.TEST: print marker, realFiles
	if canOptimize:
		# sort by directory
		realFiles.sort()
		# for optimization, group files
		cmd = theCommand
		lastDir = ""
		for curFile in realFiles:
			(dir, file) = os.path.split(curFile)
			if dir != lastDir:
				if cmd != theCommand:
					# not at the beginning: emit the command we have so far
					theOutput = theOutput + DoSingleCommand(cmd)
				# start a new session
				cmd = "cd %s; %s %s" % (dir, theCommand, file)
				lastDir = dir
			elif len(cmd) + len(file) + 1 >= CVSPrefs.maxOptimize and cmd != theCommand:
				theOutput = theOutput + DoSingleCommand(cmd)
				cmd = "cd %s; %s %s" % (dir, theCommand, file)
			else:
				cmd = cmd + " " + file
		theOutput = theOutput + DoSingleCommand(cmd)
	if CVSPrefs.TEST: print marker, "output: ",theOutput
	if showOutput==2 or (showOutput==1 and theOutput):
		CVSDialogs.ShowText("Output of "+theCommand, theOutput)
	if postCommand:
		DoSingleCommand(postCommand)
	return theOutput

#
# Internal function, will be called for each Unedit in turn
# - If deleteMode=0, keep the local copies
# - If deleteMode=1, delete the local file if the SSWE is the same
# - If deleteMode=2, ALWAYS delete the local file if same name is found in the SSWE.
#
def DoUnedit(privateRoot, SSWE, projectDir, catDir, workingFile, deleteMode):
	workingDir=vcs.joinpath(privateRoot, projectDir, catDir)
	st = vcs.get_stat(vcs.joinpath(workingDir, workingFile))
	if not vcs.test_exists(st) or vcs.test_symlink(st):
		print "@rRevert Error: %s is shared!@r" % workingFile
		return 0
	theEntry = CVSCore.GetEntry(workingDir, workingFile)
	if not theEntry:
		print "@rRevert Error: No CVS/Entry for %s!@r" % workingFile
		return 0
	# is the file modified?
	theVersion=theEntry.getVersion()
	result = CVS.cvsIsDifferent(workingDir, workingFile, theVersion)
	vcs.out=''
	vcs.err=''
	if result == 0:
		# file was not modified
		#cmd = "cd %s ; cvs -r unedit %s" % (workingDir, workingFile)
		rc = CVS.cvsUnedit(workingDir, workingFile)
	elif result == 1:
		# file WAS modified
		# here, another askQuestionDialog could be launched!
		question = "File @B%s@B was modified." % workingFile
		question = question + NL + "Are you sure you want to Unedit and loose your changes?"
		result = CVSDialogs.AskYesNoCancel("Question", question)
		if result == -1:
			return -1
		elif not result: 
			return 0
		#cmd = "cd %s ; echo 'yes' | cvs -r unedit %s" % (workingDir, workingFile)
		rc = CVS.cvsUnedit(workingDir, workingFile, 1)
	else:
		print "@rRevert Error: Cannot determine if file %s was modified!@r" % workingFile
		return 0
	#rc = vcs.system(cmd)
	if not vcs.test(rc):
		print "@rRevert Error on unedit:@r", vcs.err
		vcs.err=''
		return 0
	# perhaps remove the local file?
	if deleteMode == 0:
		return 0
	# find the file in the SSWE
	SSWElist = string.split(SSWE, vcs.DELIMITER)
	workfile = vcs.joinpath(projectDir, workingFile)
	shared_file = ''
	for SSWE in SSWElist:
		shared_file = os.path.expandvars(vcs.joinpath(SSWE,workfile))
		st = vcs.get_stat(shared_file)
		if vcs.test_exists(st):
			if SYSTEM==UNIX and os.path.islink(shared_file):
				shared_file = ''
				continue
			break
		shared_file = ''
	if not shared_file:
		return 0
	# shared file exists
	if deleteMode == 1:
		rc = vcs.system('diff %s %s' % (vcs.joinpath(workingDir, workingFile), shared_file))
		if rc != 0:
			# files in SSWE and PWE differ
			return 0
	print "Revert: removing file ",workingFile
	abs_wfile=vcs.joinpath(workingDir, workingFile)
	rc = vcs.rm_f(abs_wfile)
	if rc==0:
		CVSCore.RemoveEntry(abs_wfile)
	else:
		print "Revert: Error removing file!"
	return 0

#
# Ask the user if he is sure;
# Unedit all files found in the working paths;
# For modified files, again ask (SHOULD be yes, no, cancel, repeat; currently only yes, no)
# - If deleteMode=0, keep the local copies
# - If deleteMode=1, delete the local file if the SSWE is the same
# - If deleteMode=2, ALWAYS delete the local file if same name is found in the SSWE.
#
# Note: sniffaccess can currently not be called to update the file status.
#
def UneditFiles(privateRoot='', SSWE='', workingPaths='', deleteMode=1, theSniffaccessProjects=''):
	try:
		# the fileList is only needed for showing a nice dialog
		fileList=''
		pathList=[]
		haveMore = 0
		for curPath in string.split(workingPaths):
			(dir, file) = os.path.split(curPath)
			pathList.append( (dir,file) )
			if not fileList:
				fileList = file
			elif len(fileList) < 30:
				fileList = fileList + ', ' + file
			else:
				haveMore = 1
		if haveMore:
			fileList = fileList + ', ...'
		dialogText = 'Are you sure you want to revert the following files:' + NL + '@B' + fileList + '@B ?'
		result = CVSDialogs.AskYesNo("Question", dialogText)
		if result:
			privateRootLen = len(privateRoot)
			for curDirFile in pathList:
				(curDir, curFile) = curDirFile
				relativeDir='/'  # this is to mark an ILLEGAL directory!
				try:
					if not curDir[:privateRootLen] == privateRoot:
						print "@rRevert Error: %s is shared!@r" % curFile
					else:
						relativeDir=curDir[privateRootLen+1:]
				except:
					print "@rRevert Error: %s is shared!@r" % curFile
				if relativeDir == '/':
					# directory is ILLEGAL
					continue
				catDir=''
				result = DoUnedit(privateRoot, SSWE, relativeDir, catDir, curFile, deleteMode)
				if result < 0:
					print "Error during Unedit of ",curDirFile
					return
			curProj = ''
			try:
				for curProj in string.split(theSniffaccessProjects):
					if CVSPrefs.TEST: print "Sniffaccess update_file_info ",curProj
					etgui.Sniffaccess('update_file_info',curProj)
			except:
				if CVSPrefs.TEST: 
					print "Exception caught trying to sniffaccess update_file_info ",curProj
					traceback.print_exc()
	except:
		print "Exception caught:"
		traceback.print_exc()

def EditFiles(theFiles, theSniffaccessProjects=''):
	try:
		if CVSPrefs.DoCVSEdit:
			MultiFileCommand("cvs edit ", theFiles, 0, 1, '')
		else:
			MultiFileCommand("chmod u+w ", theFiles, 0, 1, '')
		curProj = ''
		try:
			for curProj in string.split(theSniffaccessProjects):
				if CVSPrefs.TEST: print "Sniffaccess update_file_info ",curProj
				etgui.Sniffaccess('update_file_info',curProj)
		except:
			if CVSPrefs.TEST: 
				print "Exception caught trying to sniffaccess update_file_info ",curProj
				traceback.print_exc()
	except:
		print "Exception caught:"
		traceback.print_exc()

def SetWritable(theFile, theSniffaccessProject):
	try:
		vcs.chmod(theFile,"u+w")
		try:
			if CVSPrefs.TEST: print "Sniffaccess update_file_info ",theSniffaccessProject
			etgui.Sniffaccess('update_file_info',theSniffaccessProject)
		except:
			if CVSPrefs.TEST: 
				print "Exception caught trying to sniffaccess update_file_info ",theSniffaccessProject
				traceback.print_exc()
	except:
		print "Exception caught:"
		traceback.print_exc()

def UpdateEditFile(theWorkDir, theCatDir, theFile, theSniffAccessProject):
	if theCatDir and theCatDir != '.':
		theCatFile = vcs.joinpath(theCatDir,theFile)
	else:
		theCatFile = theFile
	try:
		etgui.Sniffaccess('save_file', theSniffAccessProject, theCatFile)
		vcs.system('cd %s/%s ; cvs -r update %s' % (theWorkDir, theCatDir, theFile))
		etgui.Sniffaccess('edit_file', theSniffAccessProject, theCatFile)
	except:
		print "Exception caught:"
		traceback.print_exc()


def ConvertLabel(theLabel):
	"""Check a label for correctness and return a correct form of it"""
	tr=string.maketrans(" $,.:;@", 7*"_")
	theNewLabel = string.translate(theLabel,tr)
	firstChar = string.upper(theNewLabel[0])
	if firstChar < "A" or firstChar > "Z":
		theNewLabel = "T" + theNewLabel
	return theNewLabel

def TagFiles(theFiles, wantChangeset=0, doForce=0):
	"""Tag Files"""
	print "TagFiles successfully called."
	try:
		heading = "Enter tag name to tag current version of files (tags with same name will be replaced)"
		if wantChangeset:
			theLabel = "SNIFF_CHANGESET_"
		else:
			theLabel = ""
		theNewLabel = None
		tr=string.maketrans(" $,.:;@", 7*"_")
		while theNewLabel != theLabel:
			theNewLabel = CVSDialogs.AskQuestionDialog("Tag files", heading, theLabel)
			if not theNewLabel:
				return
			theLabel = ConvertLabel(theNewLabel)
			heading = "Please confirm translation of your label to CVS conventions:"
		if CVSPrefs.TagACL.has_key(theLabel):
			userName = CVSPrefs.GetUserName()
			if not userName in CVSPrefs.TagACL[userName]:
				print "Sorry @B", userName, "@B You are not allowed to change the label @B", theLabel, "@B."
				print "Please ask one of ",CVSPrefs.TagACL[theLabel]," for assistance!"
				return

		# BUGBUG in cvs -- workaround: do up-to-date-check externally!
		cmd = "cvs diff -rBASE "
		print "Testing up-to-date status (cvs-1.10 BUG)..."
		result = MultiFileCommand(cmd, theFiles, 1, 1)
		if string.strip(result):
			print "Error on tag -- some files seem to be modified! cvs diff output follows:"
			return
		if doForce:
			# BUGBUG in cvs -- workaround: do up-to-date-check externally!
			#cmd = "cvs tag -F -c " + theLabel + " "
			cmd = "cvs tag -F " + theLabel + " "
		else:
			# BUGBUG in cvs -- workaround: do up-to-date-check externally!
			#cmd = "cvs tag -c " + theLabel + " "
			cmd = "cvs tag " + theLabel + " "
		MultiFileCommand(cmd, theFiles, 1, 1)
	except:
		print "Exception caught:"
		traceback.print_exc()


def InitRepository(RWE):
	"""Initialize the CVS Repository"""
	try:
		theRoot = CVSDialogs.GetRepositoryDialog(RWE, "Initialize CVS Repository")
		if theRoot:
			vcs.system('cvs -d %s init' % theRoot)
	except:
		print "Exception caught:"
		traceback.print_exc()

def AddToAdminFile(theRoot, theFile, theText):
	marker="(CVSCustom) AddToAdminFile: "
	curDir = os.getcwd()
	outDir  = CVSPrefs.GetTempDir(theRoot)
	os.chdir(outDir)
	cmd = 'cvs -Q -d "%s" -w co CVSROOT' % theRoot
	(rc, out, err) = CVSCore.GetStatusOutput(cmd)
	if not vcs.test(rc): 
		print cmd
		print marker,"checkout ERROR (",rc,"): ",err
		os.chdir(curDir)
		return
	cvsrDir = vcs.joinpath(outDir, "CVSROOT")
	thePath = vcs.joinpath(cvsrDir, theFile)
	st = vcs.get_stat(thePath)
	try:
		os.chdir(cvsrDir)
		if not vcs.test_exists(st):
			if CVSPrefs.TEST: print "new file, creating..."
			f=open(thePath,"w")
			f.write(theText + NL)
			f.close()
			cmd = 'cvs add -m "new %s" %s ;' % (theFile, theFile)
		else:
			if not vcs.test_writable(st):
				EditFiles(theFile)
			f=open(theFile,"a")
			f.write(theText+NL)
			f.close()
			cmd = ''
	except IOError:
		print marker,"Cannot write file ", thePath
		os.chdir(curDir)
		return
	cmd = cmd + 'cvs commit -m "Add SNiFF+ %s" %s' % (theFile, theFile)
	(rc,out,err) = CVSCore.GetStatusOutput(cmd)
	if not vcs.test(rc):
		print cmd
		print marker,"Error committing ",theFile," (",rc,"):",err
		os.chdir(curDir)
		return
	#BUGBUG in the future, don't release it -> allows faster adminfile editing
	#os.chdir(curDir)
	#return
	# cd to a valid dir before release! Invalid one causes coredump on Windows!
	os.chdir(outDir)
	cmd = 'cvs -Q -d "%s" release -d CVSROOT' % theRoot
	(rc, out, err) = CVSCore.GetStatusOutput(cmd)
	if not vcs.test(rc):
		print cmd
		print marker, "Error releasing CVSROOT (",rc,"): ",err
	os.chdir(curDir)
	#BUGBUG for unknown reasons, this crashes SNiFF on NT!
	#vcs.rm_fr(outdir)

def AddIgnoreEntries(RWE):
	"""Add SNiFF+ cvsignore Entries"""
	try:
		(theRoot, theEntries) = CVSDialogs.RweWithTextDialog(
			RWE, 
			"Add SNiFF+ cvsignore Entries",
			"Ignores",
			".sniffdir .ProjectCache .RetrieverIndex .SniffDB\n.[sS]niff* *%" 
			)
		if theRoot:
			AddToAdminFile(theRoot, "cvsignore", theEntries)
	except:
		print "Exception caught:"
		traceback.print_exc()

def AddWrappers(RWE):
	"""Add SNiFF+ cvswrappers"""
	try:
		(theRoot, theEntries) = CVSDialogs.RweWithTextDialog(
			RWE, 
			"Add SNiFF+ cvswrappers",
			"Wrappers",
			"*.shared -m 'COPY'\n*.proj   -m 'COPY'\n*.gif    -k 'b'\n*.png    -k 'b'\n*.vcl    -k 'b'"
			)
		if theRoot:
			AddToAdminFile(theRoot, "cvswrappers", theEntries)
	except:
		print "Exception caught:"
		traceback.print_exc()

def ShowAdminFile(file, pweRoot, RWE):
	"""Show cvs admin files (cvsignore, modules)"""
	try:
		if not CVSPrefs.IsUniqueRepository(RWE):
			RWE = CVSDialogs.GetRepositoryDialog(RWE, "Choose RWE to show %s" % file)
			if not RWE: return
		theFile=vcs.getoutput('cvs -d "%s" -q checkout -p "CVSROOT/%s"' % (RWE, file))
		return CVSDialogs.ShowText("CVS %s file of %s" % (file, RWE), theFile)
	except:
		print "Exception caught:"
		traceback.print_exc()

def EditAdminFile(file, pweRoot, RWE):
	"""Start editor for cvs admin files (cvsignore, modules)"""
	try:
		marker="(CVSCustom) EditAdminFile: "
		if not CVSPrefs.IsUniqueRepository(RWE):
			RWE = CVSDialogs.GetRepositoryDialog(RWE, "Choose RWE to show %s" % file)
			if not RWE: return
		try:
			curDir = os.getcwd()
		except:
			curDir = ""
		outDir = CVSPrefs.GetTempDir(RWE)
		os.chdir(outDir)
		cmd = 'cvs -d "%s" -w co "CVSROOT/%s"' % (RWE, file)
		(rc, out, err) = CVSCore.GetStatusOutput(cmd)
		if not vcs.test(rc):
			print cmd
			print marker, "Error (",rc,"): ",err
			os.chdir(curDir)
			return
		theFile = vcs.joinpath(outDir,"CVSROOT",file)
		try:
			f=open(theFile,"r")
			data = f.read()
			f.close()
		except IOError:
			print marker, "Cannot read file"
		else:
			data = CVSDialogs.AskQuestionDialog("Edit %s file of %s" % (file, RWE), "", data, 1)
			if not data:
				if CVSPrefs.TEST: print marker, "Edit canceled"
			else:
				st = vcs.get_stat(theFile)
				if not vcs.test_writable(st):
					EditFiles(theFile)
				try:
					open(theFile,"w").write(data)
				except IOError:
					print marker, "cannot write ",theFile
				else:
					cmd = 'cvs -q commit -m "new %s file" CVSROOT/%s' % (file, file)
					(rc, out, err) = CVSCore.GetStatusOutput(cmd)
					if not vcs.test(rc):
						print cmd
						print marker, "Error (",rc,"): ",err
						os.chdir(curDir)
						return
		#BUGBUG in the future, don't release it -> allows faster adminfile editing
		#os.chdir(curDir)
		#return
		#BUGBUG don't release
		cmd = 'cvs -Q -d "%s" release -d CVSROOT' % RWE
		(rc,out,err) = CVSCore.GetStatusOutput(cmd)
		if not vcs.test(rc):
			print cmd
			print marker, "Error (",rc,"): ",err
		os.chdir(curDir)
		vcs.rm_fr(outDir)
	except:
		print "Exception caught:"
		traceback.print_exc()
 
def ToggleCVSDebugging():
	try:
		try:
			CVSPrefs.TEST = 1-CVSPrefs.TEST
		except:
			CVSPrefs.TEST = 1
		print "CVS Debugging is now ",CVSPrefs.TEST
	except:
		traceback.print_exc()
		pass
 
def ToggleVCSDebugging():
	try:
		try:
			vcs.TEST = 1-vcs.TEST
		except:
			vcs.TEST = 1
		print "vcs Adapter Debugging is now ",vcs.TEST
	except:
		traceback.print_exc()
		pass
 
def ToggleExclusiveLockers():
	try:
		try:
			CVSPrefs.LockersShowExclusive = 1 - CVSPrefs.LockersShowExclusive
		except:
			CVSPrefs.LockersShowExclusive = 1
		print "Exclusive Lockers Display is now ", CVSPrefs.LockersShowExclusive
	except:
		traceback.print_exc()
		pass

def PrintVars(*Vars):
	"""Print all Variables"""
	varNum=0
	for theVar in Vars:
		varNum = varNum + 1
		print "(CVSCustom) PrintVars ", varNum, ": ", theVar

def ShowPrefsDialog(RWE):
	"""Show the CVS Preferences Dialog"""
	if vcs.TEST: print "(CVSCustom)@B@g>>>@x ShowPreferencesDialog@B"
	try:
		# RepositoryList = CVSPrefs._TRANSLATIONS[RWE]
		RepositoryList = CVSPrefs.GetTranslations(RWE)
		# show the dialog
		import CVSPrefsDialog
		if vcs.TEST:
			vcsDebug = 1
		else:
			vcsDebug = 0
		model = CVSPrefsDialog.Show(
									RepositoryList,
									"CVSMaster",
									"CVSUser",
									"CVSProject",
									vcsDebug,
									CVSPrefs.TEST
									)
		if model != None:
			# set the global debug variables
			try:
				CVSPrefs.TEST = model.GetValue("CVSDebug")
			except ValueError:
				CVSPrefs.TEST = 0
			try:
				if model.GetValue("VCSDebug") == "1":
					vcs.TEST = 1
				else:
					vcs.TEST = ''
			except ValueError:
				pass
			if CVSPrefs.TEST:
				print "(CVS) CVSPrefs.TEST = '%d'" % CVSPrefs.TEST
				print "(CVS) vcs.TEST = '%s'" % vcs.TEST
			try:
				# write the config File
				RepositoryList = model.GetValue("Repository List")
				if vcs.TEST:
					print "(CVS)\tgot following dictionary from dialog: @B@r",
					print RepositoryList,
					print "@x@B"
				# write changes to config file
				CVSPrefs._TRANSLATIONS[RWE] = RepositoryList
			except:
				print "(CVS)cannot write Config File"
				pass
	except:
		import traceback
		print "(CVSCustom)@B@r<<<@x ShowPrefsDialog (Exception)@B"
		traceback.print_exc()
		return
	if vcs.TEST: print "(CVSCustom)@B@r<<<@x ShowPrefsDialog@B"
	return

if __name__ == '__main__':
	#retval = ShowPrefsDialog("")
	#retval = InitRepository("")
	#retval = InitRepository("@/Users/mober/TestArea/cvs2/rwefile")
	#retval = AddIgnoreEntries("@/Users/mober/TestArea/cvs2/rwefile")
	#retval = ShowAdminFile("cvsignore", "", "@/Users/mober/TestArea/cvs2/rwefile")
	#retval = EditAdminFile("modules", "C:/", "@/Users/mober/TestArea/cvs2/rwefile")
	#retval = PrintVars("Hans", "Peter", "Sepp")
	#retval = MultiFileCommand("cvs -Q status -v ", "/Users/mober/TestArea/cvs3/sswe/complex/main.C", 0, 1)
	#print retval
	#retval = MultiFileCommand("cvs -Q status -v ", 
	#	"/Users/mober/TestArea/cvs3/sswe/complex/main.C /Users/mober/TestArea/cvs3/sswe/complex/complexlib/complex.h", 1, 1)
	#retval = TagFiles("/Users/mober/TestArea/cvs3/sswe/complex/main.C")
	#retval = AddIgnoreEntries("mober@apollo:/Users/mober/TestArea/cvs5/rwe")
	#retval = EditAdminFile("cvsignore", "dummy", "mober@apollo:/Users/mober/TestArea/cvs5/rwe")
	retval = MultiFileCommand('cvs -r update ',
		'D:/home/mober/TestArea/cvs1/sswe/complex/main.C',
		1, 1) #, 'sniffaccess -q update_file_info */')
	print retval
